/**
 * Copyright 2005 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.edi.db.connection;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.edi.db.EdiDb;
import com.edi.db.cfg.Configuration;
import com.edi.db.cfg.Environment;
import com.edi.util.PropertiesHelper;
import com.edi.util.ReflectHelper;

/**
 * Instantiates a connection provider given either <tt>System</tt> properties or
 * a <tt>java.util.Properties</tt> instance. The <tt>ConnectionProviderFactory</tt>
 * first attempts to find a name of a <tt>ConnectionProvider</tt> subclass in the
 * property <tt>hibernate.connection.provider_class</tt>. If missing, heuristics are used
 * to choose either <tt>DriverManagerConnectionProvider</tt>,
 * <tt>DatasourceConnectionProvider</tt>, <tt>C3P0ConnectionProvider</tt> or
 * <tt>DBCPConnectionProvider</tt>.
 * @see ConnectionProvider
 * @author Gavin King
 */

public final class ConnectionProviderFactory {

	private static final Log log = LogFactory.getLog(ConnectionProviderFactory.class);
 
	
	/**
	 * Instantiate a <tt>ConnectionProvider</tt> using <tt>System</tt> properties.
	 * @return The created connection provider.
	 * @throws HibernateException
	 */
	public static ConnectionProvider newConnectionProvider(Configuration cfg) throws Exception {
		 
		return newConnectionProvider( cfg.getConfigPropertys() );
	}

	/**
	 * Instantiate a <tt>ConnectionProvider</tt> using given properties.
	 * Method newConnectionProvider.
	 * @param properties hibernate <tt>SessionFactory</tt> properties
	 * @return ConnectionProvider
	 * @throws Exception
	 */
	public static ConnectionProvider newConnectionProvider(Properties properties) throws Exception {
		return newConnectionProvider( properties, null );
	}

	/**
	 * Create a connection provider based on the given information.
	 *
	 * @param properties Properties being used to build the {@link org.hibernate.SessionFactory}.
	 * @param connectionProviderInjectionData Soemthing to be injected in the conenction provided
	 * @return The created connection provider
	 * @throws Exception
	 */
	public static ConnectionProvider newConnectionProvider(Properties properties, Map connectionProviderInjectionData) throws Exception {
		ConnectionProvider connections;
		String providerClass = properties.getProperty(Environment.CONNECTION_PROVIDER);
		Collection col=properties.values();
		String dbUrl=PropertiesHelper.getDbUrl(properties.getProperty(Environment.SERVER),properties.getProperty(Environment.DBNAME),properties.getProperty(Environment.USERNAME),properties.getProperty(Environment.PASSWD),properties.getProperty(Environment.DIALECT));
		String driver_class=PropertiesHelper.getDbDriver(properties.getProperty(Environment.DIALECT));
		if(dbUrl==null)
			throw new Exception("构造数据库连接池发生异常 dbUrl 为空");
		Iterator it=col.iterator();
		while(it.hasNext()){
			log.debug(" value="+(String)it.next());
		}
		log.debug("providerClass ="+providerClass);
		if(properties.getProperty(Environment.DIALECT).equals(EdiDb.DIALECT_SQLITE))
			connections = new DriverManagerConnectionProvider();
		else if ( providerClass!=null ) {
			try {
				log.info("Initializing connection provider: " + providerClass);
				connections = (ConnectionProvider) ReflectHelper.classForName(providerClass).newInstance();
			}
			catch ( Exception e ) {
				log.error( "Could not instantiate connection provider", e );
				throw new Exception("Could not instantiate connection provider: " + providerClass);
			}
		}
		else if ( properties.getProperty(Environment.JNDINAME)!=null&&!"".equals(properties.getProperty(Environment.JNDINAME)) ) {
			connections = new DatasourceConnectionProvider();
		}
		else if ( dbUrl!=null ) {
			connections = new C3P0ConnectionProvider();
		}
		else {
			throw new RuntimeException ("构造数据库连接池发生异常，缺少必要连接元素！");
		}   
		connections.configure(properties);
		return connections;
	}

	// cannot be instantiated
	private ConnectionProviderFactory() { throw new UnsupportedOperationException(); }

	/**
	 * Transform JDBC connection properties.
	 *
	 * Passed in the form <tt>hibernate.connection.*</tt> to the
	 * format accepted by <tt>DriverManager</tt> by triming the leading "<tt>hibernate.connection</tt>".
	 */
	public static Properties getConnectionProperties(Properties properties) {

		Iterator iter = properties.keySet().iterator();
		Properties result = new Properties();
		while ( iter.hasNext() ) {
			String prop = (String) iter.next();
			if ( prop.indexOf(Environment.CONNECTION_PREFIX) > -1 
//					&& !SPECIAL_PROPERTIES.contains(prop) 
					) {
				result.setProperty(
					prop.substring( Environment.CONNECTION_PREFIX.length()+1 ),
					properties.getProperty(prop)
				);
			}
		}
		String userName = properties.getProperty(Environment.USERNAME);
		if (userName!=null) result.setProperty( "user", userName );
		return result;
	}

//	private static final Set SPECIAL_PROPERTIES;
//	static {
//		SPECIAL_PROPERTIES = new HashSet();
//		SPECIAL_PROPERTIES.add(Environment.JNDINAME);
//		SPECIAL_PROPERTIES.add(Environment.SERVER);
//		SPECIAL_PROPERTIES.add(Environment.DBNAME);
//		SPECIAL_PROPERTIES.add(Environment.USERNAME);
//		SPECIAL_PROPERTIES.add(Environment.PASSWD);
//		SPECIAL_PROPERTIES.add(Environment.DIALECT);
//		SPECIAL_PROPERTIES.add(Environment.CONNECTION_PROVIDER);
//		SPECIAL_PROPERTIES.add(Environment.MAXCONNECTIONS);
//		SPECIAL_PROPERTIES.add(Environment.CONNECTIONTIMEOUT)
//		SPECIAL_PROPERTIES.add(Environment.)
////		SPECIAL_PROPERTIES.add(Environment.ISOLATION); //默认事物隔离  
//
//	}

}






